home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows Expert
/
Windows Expert.iso
/
windownt
/
wvnsrc75.zip
/
WVGROUP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-02-03
|
32KB
|
1,166 lines
/*--- wvgroup.c ------------------------------------------- */
/* This file contains the window procedure for the Group Viewing window
* for WinVN.
*/
#include <windows.h>
#ifndef MAC
#include "winundoc.h"
#endif
#include "WVglob.h"
#include "WinVn.h"
#ifdef MAC
#include "MRRM1.h"
#include <DialogMgr.h>
#endif
long NewCursorToTextLine (int X, int Y, TypDoc * DocPtr);
long search_headers (TypDoc * HeaderDoc, TypHeader *headers, long artindex, long num_headers);
LPSTR string_compare_insensitive (LPSTR a, LPSTR b);
/*--- FUNCTION: WinVnViewWndProc --------------------------------------------
*
* Window procedure for a Group window, which contains the subjects
* of the various articles in a newsgroup.
* Note that there may be several different Group windows active;
* this routine gets called any time anything happens to any of them.
*/
long FAR PASCAL
WinVnViewWndProc (hWnd, message, wParam, lParam)
HWND hWnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
FARPROC lpProcAbout;
HMENU hMenu;
PAINTSTRUCT ps; /* paint structure */
HDC hDC; /* handle to display context */
RECT clientRect; /* selection rectangle */
HDC hDCView;
TypDoc *ThisDoc;
int ih, j;
int iart;
long artindex;
int found;
int imemo;
int CtrlState;
TypBlock far *BlockPtr, far * ArtBlockPtr;
TypLine far *LinePtr, far * ArtLinePtr;
HANDLE hBlock;
unsigned int Offset;
char mybuf[MAXINTERNALLINE];
TypDoc *MyDoc;
TypLineID MyLineID;
POINT ptCursor;
int X, Y, nWidth, nHeight;
int mylen;
int OldSel = FALSE;
/* We know what *window* is being acted on, but we must find
* out which *document* is being acted on. There's a one-to-one
* relationship between the two, and we find out which document
* corresponds to this window by scanning the GroupDocs array.
*/
for (ih = 0, found = FALSE; !found && ih < MAXGROUPWNDS; ih++)
{
if (GroupDocs[ih].hDocWnd == hWnd)
{
found = TRUE;
ThisDoc = &(GroupDocs[ih]);
}
}
if (!found)
{
ThisDoc = CommDoc;
}
switch (message)
{
case WM_ACTIVATE:
if (wParam)
{
ActiveGroupDoc = ThisDoc;
#if 0
SetMenuBar (groupMenuBar);
DrawMenuBar ();
#endif
}
/* fall through */
case WM_SYSCOMMAND:
return (DefWindowProc (hWnd, message, wParam, lParam));
case WM_SIZE:
GetClientRect (hWnd, &clientRect);
ThisDoc->ScXWidth = clientRect.right;
ThisDoc->ScYHeight = clientRect.bottom;
ThisDoc->ScYLines = (clientRect.bottom - clientRect.top - TopSpace) / LineHeight;
ThisDoc->ScXChars = (clientRect.right - clientRect.left - SideSpace) / CharWidth;
break;
case WM_DESTROY:
/* Unlink all the article windows that belong to this group */
UpdateSeenArts (ThisDoc);
UnlinkArtsInGroup (ThisDoc);
ThisDoc->InUse = FALSE;
if (ThisDoc == CommDoc)
{
CommBusy = FALSE;
CommDoc = (TypDoc *) NULL;
}
/* Clear the pointer in the line for this group in the */
/* NetDoc document. This pointer currently points */
/* to the current document, which we are wiping out */
/* with the destruction of this window. */
LockLine (ThisDoc->hParentBlock, ThisDoc->ParentOffset, ThisDoc->ParentLineID, &BlockPtr, &LinePtr);
{
TypGroup far *group =
(TypGroup far *) (((char far *) LinePtr) + sizeof (TypLine));
group->SubjDoc = (TypDoc *) NULL;
/* Free the header table */
if (group->header_handle)
GlobalFree (group->header_handle);
group->header_handle = (HANDLE) NULL;
group->total_headers = 0;
}
UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
/* Clear document */
FreeDoc (ThisDoc);
/* If there's another group window, make it the active */
/* group window so we don't create a new one if the */
/* New Group flag is FALSE. */
for (j = MAXGROUPWNDS - 1; j >= 0; j--)
{
if (GroupDocs[j].InUse)
{
ActiveGroupDoc = &(GroupDocs[j]);
break;
}
}
break;
case WM_KEYDOWN:
/* See if this key should be mapped to a scrolling event
* for which we have programmed the mouse. If so,
* construct the appropriate mouse call and call the mouse code.
*/
#ifndef MAC
if (wParam == VK_F6)
{
NextWindow (ThisDoc);
}
else
{
CtrlState = GetKeyState (VK_CONTROL) < 0;
for (j = 0; j < NUMKEYS; j++)
{
if (wParam == key2scroll[j].wVirtKey &&
CtrlState == key2scroll[j].CtlState)
{
SendMessage (hWnd, key2scroll[j].iMessage,
key2scroll[j].wRequest, 0L);
break;
}
}
}
#endif
break;
case WM_CHAR:
/* Carriage Return means the same as double-clicking
* on where the cursor is currently pointing.
*/
if (wParam == '\r')
{
GetCursorPos (&ptCursor);
ScreenToClient (hWnd, &ptCursor);
#ifdef MAC
X = ptCursor.h;
Y = ptCursor.v;
#else
X = ptCursor.x;
Y = ptCursor.y;
#endif
goto getarticle;
}
else
{
}
break;
case WM_LBUTTONDOWN:
/* Clicking the left button on an article name toggles the
* selected/not selected status of that article.
* Currently selected articles are displayed in reverse video.
*/
break;
case WM_LBUTTONDBLCLK:
/* Double-clicking on an article subject creates an "Article"
* window, whose purpose is to display the article.
*/
X = LOWORD (lParam);
Y = HIWORD (lParam);
getarticle:;
artindex = NewCursorToTextLine (X, Y, ThisDoc);
if (artindex > -1 )
{
ViewArticle (ThisDoc, artindex, FALSE);
}
break;
case WM_VSCROLL:
NewScrollIt (ThisDoc, wParam, lParam);
break;
case WM_PAINT:
{
HANDLE hBlock;
int MyLen, width;
unsigned int Offset;
int VertLines, HorzChars;
int EndofDoc = FALSE;
int RangeHigh, CurPos;
int RestX, indicatorwidth, Xtext;
char far *textptr;
char indicator;
char *indcptr;
TypArticle far *MyArt;
unsigned int artindex;
long int artnum;
TypBlock far *BlockPtr;
TypLine far *LinePtr;
TypBlock far *NetBlockPtr;
TypLine far *NetLinePtr;
TypGroup far *group;
TypHeader *headers;
HANDLE header_handle;
char scratch_line [MAXINTERNALLINE];
long int OldHighestSeen;
HANDLE hBlackBrush;
DWORD MyColors[4], MyBack[4];
#ifdef MAC
RECT myRect;
POINT myPoint;
#endif
DWORD Rop;
int MyColorMask = 0;
int PrevColorMask = MyColorMask;
SIZE string_size;
/* MyColors and MyBack are arrays of colors used to display text
* foreground and background.
* The ColorMask variables are indices into these arrays.
* We set and clear bits in these indices depending upon
* whether the article has been selected or seen.
*/
#define SEEN_MASK 1
#define SELECT_MASK 2
hDC = BeginPaint (hWnd, &ps);
GetClientRect (hWnd, &clientRect);
SelectObject (hDC, hFont);
VertLines = ( (ThisDoc->ScYLines > (ThisDoc->TotalLines - ThisDoc->TopLineOrd))
? (ThisDoc->TotalLines - ThisDoc->TopLineOrd )
: ThisDoc->ScYLines);
HorzChars = ThisDoc->ScXChars;
MyColors[0] = GetTextColor (hDC); /* black */
MyColors[1] = GroupSeenColor;
MyColors[2] = GetBkColor (hDC); /* white */
MyColors[3] = MyColors[1]; /* blue */
MyBack[0] = MyColors[2];/* white */
MyBack[1] = MyColors[2];
MyBack[2] = MyColors[0];
MyBack[3] = MyColors[0];
/* LockLine (ThisDoc->hCurTopScBlock, ThisDoc->TopScOffset, ThisDoc->TopScLineID,
&BlockPtr, &LinePtr);
*/
/* Update the scroll bar thumb position. */
CurPos = ThisDoc->TopLineOrd;
if (CurPos < 0)
CurPos = 0;
RangeHigh = ThisDoc->TotalLines - VertLines;
if (RangeHigh < 0)
RangeHigh = 0;
SetScrollRange (hWnd, SB_VERT, 0, RangeHigh, FALSE);
SetScrollPos (hWnd, SB_VERT, CurPos, TRUE);
GetTextExtentPoint (hDC, "s 99999 ", 8, &string_size);
indicatorwidth = string_size.cx;
LockLine (ThisDoc->hParentBlock, ThisDoc->ParentOffset, ThisDoc->ParentLineID,
&NetBlockPtr, &NetLinePtr);
group = (TypGroup far *) ((char far *) NetLinePtr + sizeof (TypLine));
header_handle = group->header_handle;
if (header_handle)
headers = (TypHeader *) ((char *) GlobalLock (header_handle) + sizeof(char *));
OldHighestSeen = group->HighestPrevSeen;
UnlockLine (NetBlockPtr, NetLinePtr, &hBlock, &Offset, &MyLineID);
#ifdef MAC
myRect.right = ThisDoc->DocClipRect.right;
myRect.top = 0;
myRect.bottom = LineHeight;
#endif
/* Now paint this stuff on the screen. */
X = SideSpace;
Xtext = X + indicatorwidth;
Y = StartPen;
artindex = ThisDoc->TopLineOrd;
if (ThisDoc->TotalLines)
do
{
artnum = headers[artindex].number;
indicator = ' ';
if(headers[artindex].Seen) {
indicator = 's';
} else if(OldHighestSeen) {
if(headers[artindex].number > OldHighestSeen) {
indicator = 'n';
}
}
if(ThisDoc->FindOffset == artindex)
indicator = '>';
sprintf (scratch_line, "%c %u %6.6Fs %20.20Fs %4Fd %Fs ",
indicator,
headers[artindex].number,
headers[artindex].date,
headers[artindex].from,
headers[artindex].lines,
headers[artindex].subject);
MyLen = lstrlen (scratch_line);
/* Figure out the color of this line. */
if (headers[artindex].Seen)
{
MyColorMask |= SEEN_MASK;
}
else
{
MyColorMask &= (0xff - SEEN_MASK);
}
if (headers[artindex].Selected)
{
MyColorMask |= SELECT_MASK;
Rop = BLACKNESS;
}
else
{
MyColorMask &= 0xff - SELECT_MASK;
Rop = WHITENESS;
}
if (MyColorMask != PrevColorMask)
{
SetTextColor (hDC, MyColors[MyColorMask]);
SetBkColor (hDC, MyBack[MyColorMask]);
PrevColorMask = MyColorMask;
}
/* Now write out the line. */
GetTextExtentPoint (hDC, scratch_line, MyLen, &string_size);
width = string_size.cx;
TextOut (hDC, X, Y, scratch_line, MyLen);
#ifdef MAC
GetPen (&myPoint);
myRect.left = myPoint.h;
FillRect (&myRect, white);
myRect.top += LineHeight;
myRect.bottom += LineHeight;
#else
RestX = X + width;
PatBlt (hDC, RestX, Y, clientRect.right - RestX, LineHeight, Rop);
#endif
#if 0
if (MyLen < HorzChars)
{
RestX = X + width;
/* TextOut(hDC,RestX,Y,Blanks,MAXINTERNALLINE); */
PatBlt (hDC, RestX, Y, clientRect.right - RestX, LineHeight, Rop);
}
#endif
Y += LineHeight;
artindex++;
}
while (--VertLines > 0 );
if (header_handle)
GlobalUnlock (header_handle);
/* We've reached the end of the data to be displayed */
/* on this window. If there's more screen real estate */
/* left, just blank it out. */
SetTextColor (hDC, MyColors[0]);
SetBkColor (hDC, MyBack[0]);
PatBlt (hDC, 0, Y, clientRect.right, clientRect.bottom - Y, PATCOPY);
EndPaint (hWnd, &ps);
break;
}
case WM_COMMAND:
switch (wParam)
{
case IDV_EXIT:
DestroyWindow (hWnd);
break;
case IDV_NEXT:
break;
case IDM_FIND:
case IDM_FIND_NEXT_SAME:
FindDoc = ThisDoc;
if (wParam == IDM_FIND)
DialogBox (hInst, "WinVnFind", hWnd, lpfnWinVnFindDlg);
if(strcmp(FindDoc->SearchStr,"")) {
TypGroup far * group;
TypHeader *headers;
HANDLE header_handle;
int starting_at;
LockLine (ThisDoc->hParentBlock, ThisDoc->ParentOffset, ThisDoc->ParentLineID,
&BlockPtr, &LinePtr);
group = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
header_handle = group->header_handle;
headers = (TypHeader *) ((char *) GlobalLock (header_handle) + sizeof(char *));
UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
/* 'Find Next' will start one line after */
starting_at = ThisDoc->TopLineOrd + ((wParam == IDM_FIND) ? 0 : 1);
/* back up one if we're at the end */
if (starting_at >= group->total_headers)
starting_at--;
found = search_headers (ThisDoc, headers, starting_at, group->total_headers);
if (found == -1)
{
strcpy (mybuf, "\"");
strcat (mybuf, ThisDoc->SearchStr);
strcat (mybuf, "\" not found.");
MessageBox (hWnd, mybuf, "Not found", MB_OK);
}
else {
ThisDoc->TopLineOrd = found;
ThisDoc->FindOffset = found;
InvalidateRect(ThisDoc->hDocWnd,NULL,FALSE);
}
GlobalUnlock (header_handle);
}
break;
case IDV_CREATE:
/* We are creating the skeleton text of a new posting.
* Most of the work is done by CreatePostingWnd and
* CreatePostingText. Here we have to identify
* the newsgroup for those routines.
* Get the newsgroup from the line in NetDoc that
* points to this document.
*/
LockLine (ThisDoc->hParentBlock, ThisDoc->ParentOffset,
ThisDoc->ParentLineID, &BlockPtr, &LinePtr);
ExtractTextLine (ThisDoc->ParentDoc, LinePtr,
mybuf, MAXINTERNALLINE);
UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
NewsgroupsPtr = mybuf;
CreatePostingWnd ((TypDoc *) NULL, DOCTYPE_POSTING);
break;
}
break;
default:
return (DefWindowProc (hWnd, message, wParam, lParam));
}
return (0);
}
/* --- function CopyNonBlank ----------------------------------------
*
* Copy a string, terminating at the first blank or zero byte.
*
* Entry strtarg FWA of target area.
* strsource FWA of source string.
* maxchars the maximum number of characters to copy
* if no blank or zero is encountered.
*
* Exit returns the number of characters copied.
*
* I believe this routine is no longer used, but I'm leaving it here.
*/
int
CopyNonBlank (strtarg, strsource, maxchars)
char *strtarg, *strsource;
int maxchars;
{
int j;
for (j = 0; j < maxchars && strsource[j] != ' '; j++)
strtarg[j] = strsource[j];
return (j);
}
/* --- function FileLength -------------------------------------------
*
* Find the size, in bytes, of a file.
*
* Entry hFile handle of the file in question.
*
* Exit returns the length of the file in bytes.
*
* This routine is no longer used.
*/
long
FileLength (hFile)
HANDLE hFile;
{
long lCurrentPos = _llseek (hFile, 0L, 1);
long lFileLength = _llseek (hFile, 0L, 2);
_llseek (hFile, lCurrentPos, 0);
return lFileLength;
}
/*-- function ViewArticle -------------------------------------------------
*
* View a given article. Either create a new window for it or
* recycle an existing window.
* This function requests an article from the server, so there
* must not already be a transaction in progress.
*
* Entry Doc points to the document for this group.
* artindex index into header array for this group.
* Reuse is TRUE if we ought to reuse the
* currently active article window (if any).
*/
void
ViewArticle (Doc, artindex, Reuse)
TypDoc *Doc;
long artindex;
BOOL Reuse;
{
TypDoc *MyDoc;
TypGroup far *GroupDoc;
BOOL newdoc;
BOOL found;
int docnum;
HANDLE hBlock;
unsigned int Offset;
TypLineID MyLineID;
TypBlock far *BlockPtr;
TypLine far *LinePtr;
HWND hWndArt;
int width;
char mybuf[MAXINTERNALLINE];
long int artnum,oldindex;
char far *lpsz;
HWND hWndGroup = Doc->hDocWnd;
char far *lpszGroupName;
HANDLE header_handle;
TypHeader * headers;
LockLine (Doc->hParentBlock, Doc->ParentOffset, Doc->ParentLineID,
&BlockPtr, &LinePtr);
GroupDoc = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
header_handle = GroupDoc->header_handle;
headers = (TypHeader *) ((char *)GlobalLock (header_handle) + sizeof(char *)) ;
if (MyDoc = headers[artindex].ArtDoc)
{
/* We already have a document containing the article */
/* so just activate it. */
/* ShowWindow(MyDoc->hDocWnd,SW_SHOW); */
SetActiveWindow (MyDoc->hDocWnd);
SetFocus (MyDoc->hDocWnd);
goto endit;
}
if (CommBusy)
{
MessageBox (hWndGroup, "Sorry, I am already busy retrieving information from the server.\n\
Try again in a little while.", "Can't request text of article", MB_OK | MB_ICONASTERISK);
goto endit;
}
newdoc = FALSE;
if ((NewArticleWindow && !Reuse) || !ActiveArticleDoc || !(ActiveArticleDoc->InUse))
{
found = FALSE;
for (docnum = 0; docnum < MAXARTICLEWNDS; docnum++)
{
if (!ArticleDocs[docnum].InUse)
{
found = TRUE;
newdoc = TRUE;
CommDoc = &(ArticleDocs[docnum]);
break;
}
}
if (!found)
{
MessageBox (hWndGroup, "You have too many article windows \
active;\nClose one or uncheck the option \"New Window for each Article\".", "Can't open new window", MB_OK | MB_ICONASTERISK);
goto endit;
}
}
else
{
/* Must reuse old window for this article. */
CommDoc = ActiveArticleDoc;
if (CommDoc->ParentDoc == Doc) {
oldindex = CommDoc->ParentOffset; /* more slot abusage */
headers[oldindex].ArtDoc = (TypDoc *) NULL;
}
/* clear out old doc */
FreeDoc (CommDoc);
}
headers[artindex].Seen = TRUE;
InvalidateRect (hWndGroup, NULL, FALSE);
lpsz = (char far *) headers[artindex].subject;
strcpy (mybuf, "Retrieving \"");
lstrcat (mybuf, lpsz);
lstrcat (mybuf, "\"");
if (newdoc)
{
if (xScreen > 88 * CharWidth)
{
width = 88 * CharWidth;
}
else
{
width = xScreen - 1 * CharWidth;
}
hWndArt = CreateWindow ("WinVnArt",
mybuf,
WS_OVERLAPPEDWINDOW | WS_VSCROLL ,
xScreen - (width + (docnum) * CharWidth), /* Initial X pos */
(int) (yScreen * 3 / 8) + (docnum) * LineHeight, /* Initial Y pos */
(int) width, /* Initial X Width */
(int) (yScreen * 5 / 8) - (1 * LineHeight), /* Initial Y height */
NULL,
NULL,
hInst,
NULL);
if (!hWndArt)
return; /* ??? */
#ifndef MAC
ShowWindow (hWndArt, SW_SHOWNORMAL);
#else
MyShowWindow (hWndArt, SW_SHOWNORMAL);
#endif
}
else
{
hWndArt = CommDoc->hDocWnd;
SetWindowText (hWndArt, mybuf);
}
/* Now that we have created the window, create the corresponding
* document, and make the new window active.
*/
InitDoc (CommDoc, hWndArt, Doc, DOCTYPE_ARTICLE);
CommDoc->InUse = TRUE;
CommDoc->LastSeenLineID = artindex; /* Keep an index with the article */
SetActiveWindow (hWndArt);
SetFocus (hWndArt);
headers[artindex].ArtDoc = CommDoc;
CommDoc->ParentOffset = artindex;
InvalidateRect (hWndArt, NULL, FALSE);
UpdateWindow (hWndArt);
CommLinePtr = CommLineIn;
CommBusy = TRUE;
CommState = ST_ARTICLE_RESP;
/* If we're not already in this group on the server,
* send out a GROUP command for this window so we get back
* into the right Group.
*/
LockLine (Doc->hParentBlock, Doc->ParentOffset, Doc->ParentLineID,
&BlockPtr, &LinePtr);
lpszGroupName = (char far *) LinePtr + sizeof (TypLine) + sizeof (TypGroup);
if (lstrcmp (CurrentGroup, lpszGroupName))
{
CommState = ST_GROUP_REJOIN;
strcpy (mybuf, "GROUP ");
lstrcat (mybuf, lpszGroupName);
/* lstrcat(mybuf,"\r"); */
mylstrncpy (CurrentGroup, lpsz, MAXGROUPNAME);
PutCommLine (mybuf, lstrlen (mybuf));
}
UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
artnum = headers[artindex].number;
sprintf (mybuf, "ARTICLE %ld\r", artnum);
PutCommLine (mybuf, lstrlen (mybuf));
endit:
GlobalUnlock (header_handle);
}
void
view_article_by_message_id (Doc, article_request, artindex)
TypDoc *Doc;
char far * article_request;
long artindex;
{
TypDoc *MyDoc;
TypGroup far *GroupDoc;
BOOL newdoc;
BOOL found;
int docnum;
HANDLE hBlock;
unsigned int Offset;
TypLineID MyLineID;
TypBlock far *BlockPtr;
TypLine far *LinePtr;
HWND hWndArt;
int width;
char mybuf[MAXINTERNALLINE];
long int artnum;
char far *lpsz;
HWND hWndGroup = Doc->hDocWnd;
char far *lpszGroupName;
HANDLE header_handle;
TypHeader * headers;
LockLine (Doc->hParentBlock, Doc->ParentOffset, Doc->ParentLineID,
&BlockPtr, &LinePtr);
GroupDoc = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
header_handle = GroupDoc->header_handle;
headers = (TypHeader *) ((char *) GlobalLock (header_handle) + sizeof(char *)) ;
if (CommBusy)
{
MessageBox (hWndGroup, "Sorry, I am already busy retrieving information from the server.\n\
Try again in a little while.", "Can't request text of article", MB_OK | MB_ICONASTERISK);
goto endit;
}
newdoc = FALSE;
if ((NewArticleWindow) || !ActiveArticleDoc || !(ActiveArticleDoc->InUse))
{
found = FALSE;
for (docnum = 0; docnum < MAXARTICLEWNDS; docnum++)
{
if (!ArticleDocs[docnum].InUse)
{
found = TRUE;
newdoc = TRUE;
CommDoc = &(ArticleDocs[docnum]);
break;
}
}
if (!found)
{
MessageBox (hWndGroup, "You have too many article windows \
active;\nClose one or uncheck the option \"New Window for each Article\".", "Can't open new window", MB_OK | MB_ICONASTERISK);
goto endit;
}
}
else
{
/* Must reuse old window for this article. */
CommDoc = ActiveArticleDoc;
/* sever the article/artindex connection */
headers[CommDoc->ParentOffset].ArtDoc = (TypDoc *) NULL;
/* clear out old doc */
FreeDoc (CommDoc);
}
headers[artindex].Seen = TRUE;
InvalidateRect (hWndGroup, NULL, FALSE);
strcpy (mybuf, "Retrieving \"");
lstrcat (mybuf, article_request);
lstrcat (mybuf, "\"");
if (newdoc)
{
if (xScreen > 88 * CharWidth)
{
width = 88 * CharWidth;
}
else
{
width = xScreen - 1 * CharWidth;
}
hWndArt = CreateWindow ("WinVnArt",
mybuf,
WS_OVERLAPPEDWINDOW | WS_VSCROLL ,
xScreen - (width + (docnum) * CharWidth), /* Initial X pos */
(int) (yScreen * 3 / 8) + (docnum) * LineHeight, /* Initial Y pos */
(int) width, /* Initial X Width */
(int) (yScreen * 5 / 8) - (1 * LineHeight), /* Initial Y height */
NULL,
NULL,
hInst,
NULL);
if (!hWndArt)
return; /* ??? */
#ifndef MAC
ShowWindow (hWndArt, SW_SHOWNORMAL);
#else
MyShowWindow (hWndArt, SW_SHOWNORMAL);
#endif
}
else
{
hWndArt = CommDoc->hDocWnd;
SetWindowText (hWndArt, mybuf);
}
/* Now that we have created the window, create the corresponding
* document, and make the new window active.
*/
InitDoc (CommDoc, hWndArt, Doc, DOCTYPE_ARTICLE);
CommDoc->InUse = TRUE;
CommDoc->LastSeenLineID = artindex; /* Keep an index with the article */
SetActiveWindow (hWndArt);
SetFocus (hWndArt);
headers[artindex].ArtDoc = CommDoc;
InvalidateRect (hWndArt, NULL, FALSE);
UpdateWindow (hWndArt);
CommLinePtr = CommLineIn;
CommBusy = TRUE;
CommState = ST_ARTICLE_RESP;
/* If we're not already in this group on the server,
* send out a GROUP command for this window so we get back
* into the right Group.
*/
LockLine (Doc->hParentBlock, Doc->ParentOffset, Doc->ParentLineID,
&BlockPtr, &LinePtr);
lpszGroupName = (char far *) LinePtr + sizeof (TypLine) + sizeof (TypGroup);
if (lstrcmp (CurrentGroup, lpszGroupName))
{
CommState = ST_GROUP_REJOIN;
strcpy (mybuf, "GROUP ");
lstrcat (mybuf, lpszGroupName);
/* lstrcat(mybuf,"\r"); */
mylstrncpy (CurrentGroup, lpsz, MAXGROUPNAME);
PutCommLine (mybuf, lstrlen (mybuf));
}
UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
artnum = headers[artindex].number;
lstrcpy (mybuf, article_request);
PutCommLine (mybuf, lstrlen (mybuf));
endit:
GlobalUnlock (header_handle);
}
/*-- Function UnlinkArtsInGroup ---------------------------------------
*
* Modify all the article documents and all the article windows currently
* associated with a group so that none of them points to that group.
* Used when the group window is going away or is being recycled.
*
* Entry GroupDoc points to the document to which references
* should be eliminated.
*/
void
UnlinkArtsInGroup (GroupDoc)
TypDoc *GroupDoc;
{
int iart;
for (iart = 0; iart < MAXARTICLEWNDS; iart++)
{
if (ArticleDocs[iart].InUse && ArticleDocs[iart].ParentDoc == GroupDoc)
{
ArticleDocs[iart].ParentDoc = (TypDoc *) NULL;
ArticleDocs[iart].hParentBlock = 0;
}
}
}
/*--- function UpdateSeenArts -------------------------------------------
*
* Given a Group document, update the TypGroup line for
* that document in the Net document with respect to which
* articles have been seen.
* This routine would typically be called just before a Group document
* is going to be destroyed or erased. That would be the time to
* take the information in the TypArticle structures of each line
* in the document and transfer it to the line in the NetDoc document
* corresponding to this group.
*
* This routine has to take information of the form:
* 123:Unseen; 124:Seen; 125:Unseen; 126:Unseen; 127:Seen; 128:Seen; 129:Seen
* found in the TypArticle structures in consecutive lines in the document
* and transform it to the general form used by .newsrc files:
* 124,127-129
* (though we are using our internal representation & not ASCII characters).
*
* Entry Doc points to the document for this group.
*
* Exit The line in the Net document corresponding to this
* group has been updated.
*/
void
UpdateSeenArts (Doc)
TypDoc *Doc;
{
TypRange MyRange, *RangePtr;
TypGroup *group;
TypLine far *LinePtr, far * ParentLine;
TypBlock far *BlockPtr, far * ParentBlock;
HANDLE hLine,header_handle;
TypLine *LocalLinePtr;
TypHeader * headers;
TypArticle far *Art;
BOOL InSeen = TRUE;
unsigned int MyLength;
unsigned int maxRanges;
long artindex;
/* Get the line in the Net document that corresponds to this
* group. Make a local copy of it and set RangePtr to point to
* the first range in that line. We will ignore the old line's
* "seen" data and create the information afresh from what we
* have in this document.
*/
LockLine (Doc->hParentBlock, Doc->ParentOffset, Doc->ParentLineID,
&ParentBlock, &ParentLine);
hLine = LocalAlloc (LMEM_MOVEABLE, BLOCK_SIZE);
LocalLinePtr = (TypLine *) LocalLock (hLine);
group = (TypGroup *) ((char *) LocalLinePtr + sizeof (TypLine));
MoveBytes (ParentLine, LocalLinePtr, ParentLine->length);
header_handle = group->header_handle;
headers = (TypHeader *) ((char *) GlobalLock (header_handle) + sizeof (char *));
group->nRanges = 0;
maxRanges = ((Doc->BlockSize - Doc->SplitSize) - ParentLine->length +
group->nRanges * sizeof (TypRange)) / sizeof (TypRange) - 1;
RangePtr = (TypRange *) ((char *) LocalLinePtr + sizeof (TypLine) +
RangeOffset (group->NameLen));
MyRange.First = 1;
/* Get the first line in this document.
* If it cannot be found, just set Last=First and skip the
* proceeding processing. Otherwise, assume we've seen everything
* up to but not including the first article in the document.
*/
/* LockLine (Doc->hFirstBlock, sizeof (TypBlock), 0L, &BlockPtr, &LinePtr); */
artindex = 0;
if (!Doc->TotalLines)
{
MyRange.Last = 1;
}
else
{
MyRange.Last = headers[artindex].number - 1;
/* Loop to scan through the document, fabricating article ranges.
*/
do
{
if (headers[artindex].Seen)
{
if (InSeen)
{
/* Continuing a sequence of seen articles. */
MyRange.Last = headers[artindex].number;
}
else
{
/* Starting a new sequence of seen articles. */
MyRange.First = headers[artindex].number;
MyRange.Last = headers[artindex].number;
InSeen = TRUE;
}
}
else
{
if (InSeen)
{
/* Ending a sequence of seen articles. */
InSeen = FALSE;
*(RangePtr++) = MyRange;
(group->nRanges)++;
}
else
{
/* Continuing a sequence of unseen articles. */
}
}
}
while ((group->nRanges < maxRanges) &&
((++artindex < Doc->TotalLines)));
if (InSeen)
{
*(RangePtr++) = MyRange;
(group->nRanges)++;
}
}
MyLength = sizeof (TypLine) + RangeOffset (group->NameLen) +
sizeof (TypRange) * (group->nRanges) + sizeof (int);
LocalLinePtr->length = MyLength;
*(int *) ((char *) LocalLinePtr + MyLength - sizeof (int)) = MyLength;
ReplaceLine (LocalLinePtr, &ParentBlock, &ParentLine);
GlobalUnlock (ParentBlock->hCurBlock);
LocalUnlock (hLine);
LocalFree (hLine);
}
/*-- function CursorToTextLine ----------------------------------------
*
* Routine to locate a text line in a document, based on the
* cursor position. Used to figure out which line is being selected
* when a user clicks a mouse button.
*
* Entry X, Y are the position of the cursor.
* DocPtr points to the current document.
*
* Exit *LinePtr points to the current line, if one was found.
* *BlockPtr points to the current block, if found.
* Function returns TRUE iff a line was found that corresponds
* to the cursor position.
*/
long
NewCursorToTextLine (X, Y, DocPtr)
int X;
int Y;
TypDoc *DocPtr;
{
int found;
int SelLine;
if (Y < TopSpace || Y > TopSpace + DocPtr->ScYLines * LineHeight ||
X < SideSpace)
{
/* Cursor is in no-man's-land at edge of window. */
return(-1);
}
else
{
SelLine = (Y - TopSpace) / LineHeight;
return ( DocPtr->TopLineOrd + SelLine);
}
}
long
search_headers (TypDoc * HeaderDoc,
TypHeader *headers,
long artindex,
long num_headers)
{
do {
if (string_compare_insensitive (headers[artindex].subject,
HeaderDoc->SearchStr))
return (artindex); /* return the index */
} while (artindex++ < (num_headers - 1));
return (-1); /* not found */
}
LPSTR
string_compare_insensitive (LPSTR a, LPSTR b)
{
int lena = lstrlen (a);
int lenb = lstrlen (b);
int count;
for ( count = lena - lenb + 1 ; count > 0 ; count--, a++)
if (_strnicmp (a,b,lenb) == 0)
return a;
return (NULL);
}